package com.dldata.devtools30.repository.common;


import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by zhangyy on 2017-05-18.
 */
@Transactional
@Component("dlBaseJdbcTemplate")
@Setter
@Getter
public class DlBaseJdbcTemplate implements InitializingBean {
    
    //    @Resource(name = "dlJdbcCharset")
    @Autowired(required = false)
    @Qualifier("dlJdbcCharset")
    public Charset charset;
    
    @Autowired
    private SpringJdbcTemple springJdbcTemple;
    
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    
    public List<Map<String, Object>> queryForList(String sql, Object... args) throws DataAccessException {
        logger.debug("querySql: "+sql);
        logger.debug("queryArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForList(sql, args);
    }
    
    
    public List<Map<String, Object>> queryForList(String sql) throws DataAccessException {
        logger.debug("querySql: "+sql);
        return springJdbcTemple.queryForList(sql);
    }
    
    
    public int update(String sql, Object... args) throws DataAccessException {
        logger.debug("updateSql: "+sql);
        logger.debug("updateArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.update(sql, args);
    }
    
    
    public int update(String sql) throws DataAccessException {
        logger.debug("updateSql: "+sql);
        return springJdbcTemple.update(sql);
    }
    
    public void setIgnoreWarnings(boolean ignoreWarnings) {
        springJdbcTemple.setIgnoreWarnings(ignoreWarnings);
    }
    
    
    public boolean isIgnoreWarnings() {
        return springJdbcTemple.isIgnoreWarnings();
    }
    
    
    public void setFetchSize(int fetchSize) {
        springJdbcTemple.setFetchSize(fetchSize);
    }
    
    
    public int getFetchSize() {
        return springJdbcTemple.getFetchSize();
    }
    
    
    public void setMaxRows(int maxRows) {
        springJdbcTemple.setMaxRows(maxRows);
    }
    
    
    public int getMaxRows() {
        return springJdbcTemple.getMaxRows();
    }
    
    
    public void setQueryTimeout(int queryTimeout) {
        springJdbcTemple.setQueryTimeout(queryTimeout);
    }
    
    
    public int getQueryTimeout() {
        return springJdbcTemple.getQueryTimeout();
    }
    
    
    public void setSkipResultsProcessing(boolean skipResultsProcessing) {
        springJdbcTemple.setSkipResultsProcessing(skipResultsProcessing);
    }
    
    
    public boolean isSkipResultsProcessing() {
        return springJdbcTemple.isSkipResultsProcessing();
    }
    
    
    public void setSkipUndeclaredResults(boolean skipUndeclaredResults) {
        springJdbcTemple.setSkipUndeclaredResults(skipUndeclaredResults);
    }
    
    
    public boolean isSkipUndeclaredResults() {
        return springJdbcTemple.isSkipUndeclaredResults();
    }
    
    
    public void setResultsMapCaseInsensitive(boolean resultsMapCaseInsensitive) {
        springJdbcTemple.setResultsMapCaseInsensitive(resultsMapCaseInsensitive);
    }
    
    
    public boolean isResultsMapCaseInsensitive() {
        return springJdbcTemple.isResultsMapCaseInsensitive();
    }
    
    
    public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
        return springJdbcTemple.execute(action);
    }
    
    public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        return springJdbcTemple.execute(action);
    }
    
    
    public void execute(String sql) throws DataAccessException {
        logger.debug("sql: "+sql);
        springJdbcTemple.execute(sql);
    }
    
    
    public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.query(sql, rse);
    }
    
    
    public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
        logger.debug("sql: "+sql);
        springJdbcTemple.query(sql, rch);
    }
    
    
    public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.query(sql, rowMapper);
    }
    
    
    public Map<String, Object> queryForMap(String sql) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.queryForMap(sql);
    }
    
    
    public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.queryForObject(sql, rowMapper);
    }
    
    
    public <T> T queryForObject(String sql, Class<T> requiredType) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.queryForObject(sql, requiredType);
    }
    
    
    public <T> List<T> queryForList(String sql, Class<T> elementType) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.queryForList(sql, elementType);
    }
    
    
    public SqlRowSet queryForRowSet(String sql) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.queryForRowSet(sql);
    }
    
    @Transactional(propagation= Propagation.NOT_SUPPORTED)
    public int[] batchUpdate(String[] sql) throws DataAccessException {
        logger.debug("sqls: "+ StringUtils.arrayToDelimitedString(sql, ","));
        return springJdbcTemple.batchUpdate(sql);
    }
    
    
    public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
        return springJdbcTemple.execute(psc, action);
    }
    
    
    public <T> T execute(String sql, PreparedStatementCallback<T> action) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.execute(sql, action);
    }
    
    
    public <T> T query(PreparedStatementCreator psc, PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException {
        return springJdbcTemple.query(psc, pss, rse);
    }
    
    
    public <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse) throws DataAccessException {
        return springJdbcTemple.query(psc, rse);
    }
    
    
    public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.query(sql, pss, rse);
    }
    
    
    public <T> T query(String sql, Object[] args, int[] argTypes, ResultSetExtractor<T> rse) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.query(sql, args, argTypes, rse);
    }
    
    
    public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.query(sql, args, rse);
    }
    
    
    public <T> T query(String sql, ResultSetExtractor<T> rse, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.query(sql, rse, args);
    }
    
    
    public void query(PreparedStatementCreator psc, RowCallbackHandler rch) throws DataAccessException {
        springJdbcTemple.query(psc, rch);
    }
    
    
    public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException {
        logger.debug("sql: "+sql);
        springJdbcTemple.query(sql, pss, rch);
    }
    
    
    public void query(String sql, Object[] args, int[] argTypes, RowCallbackHandler rch) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        springJdbcTemple.query(sql, args, argTypes, rch);
    }
    
    
    public void query(String sql, Object[] args, RowCallbackHandler rch) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        springJdbcTemple.query(sql, args, rch);
    }
    
    
    public void query(String sql, RowCallbackHandler rch, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        springJdbcTemple.query(sql, rch, args);
    }
    
    
    public <T> List<T> query(PreparedStatementCreator psc, RowMapper<T> rowMapper) throws DataAccessException {
        return springJdbcTemple.query(psc, rowMapper);
    }
    
    
    public <T> List<T> query(String sql, PreparedStatementSetter pss, RowMapper<T> rowMapper) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.query(sql, pss, rowMapper);
    }
    
    
    public <T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.query(sql, args, argTypes, rowMapper);
    }
    
    
    public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.query(sql, args, rowMapper);
    }
    
    
    public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.query(sql, rowMapper, args);
    }
    
    
    public <T> T queryForObject(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForObject(sql, args, argTypes, rowMapper);
    }
    
    
    public <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForObject(sql, args, rowMapper);
    }
    
    
    public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForObject(sql, rowMapper, args);
    }
    
    
    public <T> T queryForObject(String sql, Object[] args, int[] argTypes, Class<T> requiredType) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForObject(sql, args, argTypes, requiredType);
    }
    
    
    public <T> T queryForObject(String sql, Object[] args, Class<T> requiredType) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForObject(sql, args, requiredType);
    }
    
    
    public <T> T queryForObject(String sql, Class<T> requiredType, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForObject(sql, requiredType, args);
    }
    
    
    public Map<String, Object> queryForMap(String sql, Object[] args, int[] argTypes) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForMap(sql, args, argTypes);
    }
    
    
    public Map<String, Object> queryForMap(String sql, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForMap(sql, args);
    }
    
    
    public <T> List<T> queryForList(String sql, Object[] args, int[] argTypes, Class<T> elementType) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForList(sql, args, argTypes, elementType);
    }
    
    
    public <T> List<T> queryForList(String sql, Object[] args, Class<T> elementType) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForList(sql, args, elementType);
    }
    
    
    public <T> List<T> queryForList(String sql, Class<T> elementType, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForList(sql, elementType, args);
    }
    
    
    public List<Map<String, Object>> queryForList(String sql, Object[] args, int[] argTypes) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForList(sql, args, argTypes);
    }
    
    
    public SqlRowSet queryForRowSet(String sql, Object[] args, int[] argTypes) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForRowSet(sql, args, argTypes);
    }
    
    
    public SqlRowSet queryForRowSet(String sql, Object... args) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.queryForRowSet(sql, args);
    }
    
    public int update(PreparedStatementCreator psc) throws DataAccessException {
        return springJdbcTemple.update(psc);
    }
    
    
    public int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder) throws DataAccessException {
        return springJdbcTemple.update(psc, generatedKeyHolder);
    }
    
    
    public int update(String sql, PreparedStatementSetter pss) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.update(sql, pss);
    }
    
    
    public int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {
        logger.debug("sql: "+sql);
        logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(args, ","));
        return springJdbcTemple.update(sql, args, argTypes);
    }
    
    
    public int[] batchUpdate(String sql, BatchPreparedStatementSetter pss) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.batchUpdate(sql, pss);
    }
    
    
    public int[] batchUpdate(String sql, List<Object[]> batchArgs) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.batchUpdate(sql, batchArgs);
    }
    
    
    public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes) throws DataAccessException {
        logger.debug("sql: "+sql);
        int lognumber=0;
        for (Iterator<Object[]> iterator = batchArgs.iterator(); iterator.hasNext(); ) {
            lognumber++;
            if(lognumber>3){
                logger.debug("onlylogger 3 batchArgs size "+batchArgs.size());
                break;
            }
            Object[] next = iterator.next();
            logger.debug("sqlArgs: "+ StringUtils.arrayToDelimitedString(next, ","));
        }
        return springJdbcTemple.batchUpdate(sql, batchArgs, argTypes);
    }
    
    
    public <T> int[][] batchUpdate(String sql, Collection<T> batchArgs, int batchSize, ParameterizedPreparedStatementSetter<T> pss) throws DataAccessException {
        logger.debug("sql: "+sql);
        return springJdbcTemple.batchUpdate(sql, batchArgs, batchSize, pss);
    }
    
    
    public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action) throws DataAccessException {
        return springJdbcTemple.execute(csc, action);
    }
    
    
    public <T> T execute(String callString, CallableStatementCallback<T> action) throws DataAccessException {
        logger.debug("sql: "+callString);
        return springJdbcTemple.execute(callString, action);
    }
    
    
    public Map<String, Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters) throws DataAccessException {
        return springJdbcTemple.call(csc, declaredParameters);
    }
    
    public void setDataSource(DataSource dataSource) {
        springJdbcTemple.setDataSource(dataSource);
    }
    
    
    public DataSource getDataSource() {
        return springJdbcTemple.getDataSource();
    }
    
    
    public void setDatabaseProductName(String dbName) {
        springJdbcTemple.setDatabaseProductName(dbName);
    }
    
    
    public void setExceptionTranslator(SQLExceptionTranslator exceptionTranslator) {
        springJdbcTemple.setExceptionTranslator(exceptionTranslator);
    }
    
    
    public synchronized SQLExceptionTranslator getExceptionTranslator() {
        return springJdbcTemple.getExceptionTranslator();
    }
    
    
    public void setLazyInit(boolean lazyInit) {
        springJdbcTemple.setLazyInit(lazyInit);
    }
    
    
    public boolean isLazyInit() {
        return springJdbcTemple.isLazyInit();
    }
    
    public void afterPropertiesSet() {
        springJdbcTemple.setUserCharset(DlBaseJdbcTemplate.this.charset);
    }
    
    public Charset getCharset() {
        return charset;
    }
    
    @Transactional
    @Repository
    public static class SpringJdbcTemple extends JdbcTemplate{
        
        private Charset[] charset=new Charset[1];
        
        
        public SpringJdbcTemple(@Autowired DataSource dataSource){
            super(dataSource);
        }
        
        @Resource
        public void setDataSource(@Autowired DataSource dataSource) {
            super.setDataSource(dataSource);
        }
        
        @Override
        protected RowMapper<Map<String, Object>> getColumnMapRowMapper() {
            ColumnMapRowMapper columnMapRowMapperDl = new ColumnMapRowMapper();
            return columnMapRowMapperDl;
        }
        
        @Override
        protected <T> RowMapper<T> getSingleColumnRowMapper(Class<T> requiredType) {
            SingleColumnRowMapper columnRowMapperDl = new SingleColumnRowMapper(requiredType);
            return columnRowMapperDl;
        }
        
        public void setUserCharset(Charset pCharset){
            this.charset[0]=pCharset==null?null:Charset.forName(pCharset.name());
        }
        
    }
}
